package com.pactera.asmp.server.job.dispatch.impl.distribute;

import com.alibaba.fastjson.JSONObject;
import com.pactera.asmp.server.common.constants.*;
import com.pactera.asmp.server.common.logprint.utils.CollectionUtils;
import com.pactera.asmp.server.common.logprint.utils.StringUtils;
import com.pactera.asmp.server.entity.Subtask;
import com.pactera.asmp.server.entity.SubtaskDistribute;
import com.pactera.asmp.server.entity.TaskDTO;
import com.pactera.asmp.server.entity.TaskDevice;
import com.pactera.asmp.server.job.dispatch.BaseDispatchBus;
import com.pactera.asmp.server.job.dispatch.IDeviceEvent;
import com.pactera.asmp.server.job.dispatch.ITaskEvent;
import com.pactera.asmp.server.job.dispatch.impl.AsmpTaskDispatchBus;
import com.pactera.asmp.server.job.dispatch.impl.BaseManager;
import com.pactera.asmp.server.pojo.DeviceInfo;
import com.pactera.asmp.server.pojo.ScriptInfo2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 *分发管理器
 */
@Slf4j
@Component
public class DistributeManager extends BaseManager {


    @Autowired
    private DistributeDataRepository repository;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final long REDIS_KEY_DUID_EXPIRE_SECOND= 10;

    public static final String JOB_SUBTASK_DISTRIBUTE_INSTANCE = "JOB_SUBTASK_DISTRIBUTE_INSTANCE";

    public static final int SUBTASK_LEN = 10;
    private static final int SUPPORT_CAN_VALUE = 1;
    private static final int SUPPORT_AUXILIARY_VALUE = 1;
    private static final String SEPARATOR = ",";


    @Override
    protected BaseDispatchBus initDispatcher() {
        return AsmpTaskDispatchBus.getDispatchBus();
    }

    @Override
    public void deviceEventHandler(IDeviceEvent event) {
        if (event.getType().equals(DeviceEventType.DEVICE_OCCUPY)) {
            //处理设备已抢占， 给这个设备分配subtask
            handleDeviceOccupy(event);
        }
        if (event.getType().equals(DeviceEventType.DEVICE_FREE)) {
            //设备空闲， 给这个设备分配subtask
            handleDeviceFree(event);
        }
        if (event.getType().equals(DeviceEventType.DEVICE_ONLINE)) {
            //要先取消之前的设备任务
            //设备上线， 给这个设备分配subtask
            handleDeviceFree(event);
        }
        if (event.getType().equals(DeviceEventType.DEVICE_OFFLINE)) {
            //设备断线， 找到这个断线设备执行的subtask, 更新状态，如果有设备空闲重新分配
            handleDeviceOffline(event);
        }
    }

    @Override
    public void taskHandler(ITaskEvent event) {
        if (event.getType().equals(TaskEventType.TASK_CREATE)) {
            //初始化subtaskDistribute
            handleTaskCreate(event);
        }
        if (event.getType().equals(TaskEventType.SUBTASK_SEND)) {
            //发送上位机,更新状态
            handleSubtaskSend(event);
        }
        if (event.getType().equals(TaskEventType.SUBTASK_EXEC)) {
            //子任务执行,更新状态
            handleSubtaskExec(event);
        }
        if (event.getType().equals(TaskEventType.SUBTASK_SUCCESS)) {
            //子任务完成, 更新状态，subtaskDistribute,task 数量字段
            handleSubtaskSuccess(event);
        }

        if (event.getType().equals(TaskEventType.TASK_CANCEL)){
            //任务取消
            handleTaskCancel(event);
        }
    }

    private void handleTaskCancel(ITaskEvent event){
        TaskDTO task =  JSONObject.parseObject(event.getData(), TaskDTO.class);
        List<Subtask> subtaskList = repository.getSubtaskListByTaskId(task.getId().longValue());
        if(CollectionUtils.isEmpty(subtaskList)){
            return ;
        }
        for(Subtask subtask : subtaskList){
            if(! subtask.getTaskStatus().equals(SubTaskStatus.SUCCESS.getValue())
                    && ! subtask.getTaskStatus().equals(SubTaskStatus.FAIL.getValue())
                    && ! subtask.getTaskStatus().equals(SubTaskStatus.FAIL_CANCEL_SEND.getValue())){
                try {
                    if(StringUtils.isNotEmpty(subtask.getDuid())){
                        //清除设备任务
                        sendTaskEvent(subtask, TaskEventType.SUBTASK_DEVICE_CLEAR);
                        subtask.setTaskStatus(SubTaskStatus.FAIL_WAIT_CANCEL.getValue());
                    }else {
                        subtask.setTaskStatus(SubTaskStatus.FAIL.getValue());
                    }
                    repository.saveSubtask(subtask);
                } catch (Exception e) {
                    log.error("handleTaskCancel saveSubtask error ",e);
                    this.retry(event);
                    return;
                }
            }
        }
    }

    private void handleSubtaskSuccess(ITaskEvent event){
        Subtask st = JSONObject.parseObject(event.getData(), Subtask.class);
        st.setTaskStatus(SubTaskStatus.SUCCESS.getValue());
        try {
            repository.saveSubtask(st);
        }catch (Exception e){
            log.error("saveSubtask: error", e);
            this.retry(event, 1000L);
        }
    }

    private void handleSubtaskSend(ITaskEvent event){
        Subtask st = JSONObject.parseObject(event.getData(), Subtask.class);
        st.setTaskStatus(SubTaskStatus.SEND.getValue());
        try {
            repository.saveSubtask(st);
        }catch (Exception e){
            log.error("saveSubtask: error", e);
        }
    }

    private void handleSubtaskExec(ITaskEvent event){
        Subtask st = JSONObject.parseObject(event.getData(), Subtask.class);
        st.setTaskStatus(SubTaskStatus.EXEC.getValue());
        try {
            repository.saveSubtask(st);
        }catch (Exception e){
            log.error("saveSubtask: error", e);
        }
    }

    private void handleDeviceOffline(IDeviceEvent event) {
        TaskDevice taskDevice = JSONObject.parseObject(event.getData(), TaskDevice.class);
        DeviceInfo device = repository.getDeviceByDuid(event.getDuid());
        if (DeviceStatus.OFFLINE.getValue() != device.getStatus()) { //不是断线
            return;
        }
        TaskDTO histTaskById = repository.getHistTaskById(taskDevice.getTaskId().intValue());
        if(histTaskById== null){
            return;
        }
        if(histTaskById.getType() == 3 || histTaskById.getType() == 4){
            return;
        }
        if(histTaskById.getStatus() == TaskStatus.TASK_CANCEL.getValue() ||
                histTaskById.getStatus() == TaskStatus.TASK_FAIL.getValue() ||
                histTaskById.getStatus() == TaskStatus.TASK_COMPLETE.getValue()){
            return;
        }
        //根据taskId和duid, 找到subtask, 更新状态，然后复制一个subtask，填上值origin_id, stats,入库
        List<Subtask> list = repository.getExecSubtaskByTaskIdAndDuid(device.getDuid(), taskDevice.getTaskId());
        if(CollectionUtils.isEmpty(list)){
            return ;
        }
        Subtask subtask = null;
        //可能会有2个，一个执行完的，一个
        for(Subtask st : list){
            if(st.getTaskStatus().equals(SubTaskStatus.DISPATCH.getValue())){
                //没发送出来，所以更新状态
                st.setTaskStatus(SubTaskStatus.CREATE.getValue());
                st.setDuid("");
                try {
                    repository.saveSubtask(st);
                }catch (Exception e){
                    log.error("saveSubtask error",e);
                }
            }else{
                //发送了，有可能已执行
                subtask = st;
            }
        }
        if(subtask == null){
            return;
        }
        subtask.setTaskStatus(SubTaskStatus.FAIL.getValue());
        subtask.setFailReason("device offline");//FIXME 整理code
        subtask.setUpdateTime(new Date());
        Subtask restrySubtask = new Subtask();
        BeanUtils.copyProperties(subtask, restrySubtask);
        restrySubtask.setRetryOriginId(subtask.getId());
        restrySubtask.setDuid(StringUtils.EMPTY);
        restrySubtask.setTaskStatus(SubTaskStatus.RETRY.getValue());
        restrySubtask.setSuccessTimes(0);
        restrySubtask.setFailTimes(0);
        restrySubtask.setId(null);
        SubtaskDistribute sd = repository.getSubtaskDistributeByTaskId(subtask.getTaskId());
        if(sd == null){
            return;
        }
        if(sd.getRemainSum() == 0){
            //只有在分配完毕情况，才有占有且空闲的机器
            List<TaskDevice> freeDeviceList = repository.getFreeDeviceByTaskId(subtask.getTaskId().intValue());
            if(CollectionUtils.isNotEmpty(freeDeviceList)) {
                //找到合适的DEVICE
                TaskDevice tdForRetry = null;
                //如果task支持
                if(isTaskSupportCanOrAuxiliary(sd)) {
                    for (TaskDevice td : freeDeviceList) {
                        //子任务需要can和aux
                        if (restrySubtask.getNeedCan() > 0 && restrySubtask.getNeedAuxiliary() > 0) {
                            //设备支持can和aux
                            if (isDeviceSupportCanAndAuxiliary(taskDevice)){
                                tdForRetry = td;
                                break;
                            }
                        }
                        //子任务需要can, 设备支持can
                        if(restrySubtask.getNeedCan() > 0 && isDeviceSupportCan(td)){
                            tdForRetry = td;
                            break;
                        }
                        //子任务需要aux，设备支持aux
                        if(restrySubtask.getNeedAuxiliary() > 0 && isDeviceSupportAuxiliary(td)){
                            tdForRetry = td;
                            break;
                        }
                        //子任务不需要can和aux
                        if(restrySubtask.getNeedCan() == 0 && restrySubtask.getNeedAuxiliary() == 0){
                            tdForRetry = td;
                            break;
                        }
                    }
                }else {
                    tdForRetry = freeDeviceList.get(0);
                }
                if(tdForRetry != null) {
                    restrySubtask.setTaskStatus(SubTaskStatus.DISPATCH.getValue());
                    restrySubtask.setDuid(tdForRetry.getDuid());
                }
            }
        }
        try {
            repository.saveRetrySubtask(subtask, restrySubtask);
        }catch (Exception e){
            log.error("saveRetrySubtask error", e);
            //DB失败，重试
            this.retry(event,1000L);
            return ;
        }
        //是否分发
        if(restrySubtask.getTaskStatus().equals(SubTaskStatus.DISPATCH.getValue())){
            sendTaskEvent(restrySubtask, TaskEventType.SUBTASK_DISPATCH, event);
        }

    }

    //分配subtask
    private void handleDeviceFree(IDeviceEvent event) {
        TaskDevice taskDevice = JSONObject.parseObject(event.getData(), TaskDevice.class);
        TaskDTO histTaskById = repository.getHistTaskById(taskDevice.getTaskId().intValue());
        if(histTaskById== null){
            return;
        }
        if(histTaskById.getType() == 3 || histTaskById.getType() == 4){
            return;
        }
        if(histTaskById.getStatus() == TaskStatus.TASK_CANCEL.getValue() ||
                histTaskById.getStatus() == TaskStatus.TASK_FAIL.getValue() ||
                histTaskById.getStatus() == TaskStatus.TASK_COMPLETE.getValue()){
            return;
        }
        distributeSubtask(event, taskDevice);
    }

    //分配subtask
    private void handleDeviceOccupy(IDeviceEvent event) {
        String duid = event.getDuid();
        log.info("分配subtask, {}", duid);
        TaskDevice taskDevice = JSONObject.parseObject(event.getData(), TaskDevice.class);

        distributeSubtask(event, taskDevice);
    }


    private void distributeSubtask(IDeviceEvent event, TaskDevice taskDevice) {
        boolean saveSuceess = false;
        //加锁，锁sd的Id
        long startTime = System.currentTimeMillis();
        boolean lock = tryLock(taskDevice.getTaskId().toString());
        if(lock){
            try {
                //查出subtaskDistribut 通过taskId
                SubtaskDistribute sd = repository.getSubtaskDistributeByTaskId(taskDevice.getTaskId());
                log.info("添加子任务，subtaskDistribute {}", JSONObject.toJSONString(sd));
                List<Subtask> addList = new ArrayList<>();
                RetryToDispatchGroup retryGroup = new RetryToDispatchGroup();
                WaitToDispatchGroup waitGroup = new WaitToDispatchGroup();
                build(retryGroup, taskDevice.getTaskId());
                build(waitGroup, taskDevice.getTaskId());
                Subtask subtask = getDisptchSubtaskByEquipPrior(retryGroup, waitGroup, taskDevice, sd);
                if (subtask == null) {
                    subtask = createAndGenerateSubtaskList(taskDevice, sd, addList);
                } else {
                    subtask.setDuid(taskDevice.getDuid());
                    subtask.setTaskStatus(SubTaskStatus.DISPATCH.getValue());
                    addList.add(subtask);
                }
                log.info("添加子任务， subtask:{}", JSONObject.toJSONString(subtask));
                //如果分配完毕，会空
                if (CollectionUtils.isEmpty(addList)) {
                    return;
                }
                //分配数量
                sd.setDistributeCount(sd.getDistributeCount()+1);
                //事务，入库， 添加subtask，和 修改sd
                //   如果成功，发事件
                //   如果失败，重新发起事件
                try {
                    saveSuceess = repository.saveSubtaskAndSD(sd, addList);
                } catch (Exception e) {
                    log.error("saveSubtaskAndSD error:", e);
                }
                log.info("saveSuceess:{}, subtask:{}", saveSuceess, JSONObject.toJSONString(subtask));
                if (saveSuceess && subtask != null) {
                    sendTaskEvent(subtask, TaskEventType.SUBTASK_DISPATCH, event);
                }
            } catch (Exception e) {
                log.error("error:",e);
            } finally {
                long useTime = System.currentTimeMillis() - startTime;
                //是否超时
                if(useTime < REDIS_KEY_DUID_EXPIRE_SECOND * 1000 ) {
                    unLock(taskDevice.getTaskId().toString());
                }else{
                    log.error("分配过程中redis锁超时解除，taskid={}", taskDevice.getTaskId());
                }
            }
            if(!saveSuceess){
                retry(event,1000L);
            }
        }else{
            retry(event,500L);
        }
    }

    /*private void sleep(Long time){
        try {
            Thread.sleep(time);
        }catch (InterruptedException e){
            log.error("sleep error",e);
        }
    }*/

    private Subtask  createAndGenerateSubtaskList(TaskDevice taskDevice, SubtaskDistribute sd, List<Subtask> addList){
        ////创建待分发，如果支持，那么发送
        //有设备支持的情况下，
        //      第一包脚本是否需要支持，
        //             如果需要，那么等待，然后接着分，直到不需要等待--循环
        //没有设备支持情况下，直接第一包创建
        if(isTaskSupportCanOrAuxiliary(sd)){
            List<String> canIds = getScriptIdListByParse(sd.getCanScriptIds());
            List<String> auxIds = getScriptIdListByParse(sd.getAuxiliaryScriptIds());
            while(true) {
                Subtask sk = createAndBuildSubtask(sd, taskDevice.getDuid());
                if(sk == null){
                    break;
                }
                addList.add(sk);
                //当前设备不支持all
                if (!isDeviceSupportCanAndAuxiliary(taskDevice)) {
                    //是否脚本需要all，需要true（要等）, 不需要false
                    boolean wait = isScriptNeedAllBySubtask(sk, canIds,auxIds);
                    if(wait){
                        //需等到
                        sk.setDuid(StringUtils.EMPTY);
                        sk.setNeedCan(SUPPORT_CAN_VALUE);
                        sk.setNeedAuxiliary(SUPPORT_AUXILIARY_VALUE);
                        continue;
                    }
                }
                //当前设备不支持can
                if (!isDeviceSupportCan(taskDevice)) {
                    //是否脚本需can，需要true, 不需要false
                    boolean wait = isScriptNeedCanBySubtask(sk, canIds);
                    if(wait){
                        sk.setDuid(StringUtils.EMPTY);
                        sk.setNeedCan(SUPPORT_CAN_VALUE);
                        continue;
                    }
                }
                //当前设备不支持aux
                if (!isDeviceSupportAuxiliary(taskDevice)) {
                    //是否脚本需aux，需要true, 不需要false
                    boolean wait = isScriptNeedAuxBySubtask(sk, auxIds);
                    if(wait){
                        sk.setDuid(StringUtils.EMPTY);
                        sk.setNeedAuxiliary(SUPPORT_AUXILIARY_VALUE);
                        continue;
                    }
                }
                sk.setTaskStatus(SubTaskStatus.DISPATCH.getValue());
                return sk;
            }
        }else {
            Subtask subtask = createAndBuildSubtask(sd, taskDevice.getDuid());
            if(subtask == null){
                return null;
            }
            subtask.setTaskStatus(SubTaskStatus.DISPATCH.getValue());
            addList.add(subtask);
            return subtask;
        }
        return null;
    }



    private Subtask createAndBuildSubtask(SubtaskDistribute sd, String duid){
        //剩余脚本为0
        if(sd.getRemainSum() == 0){
            return null;
        }
        Subtask subtask = new Subtask();
        subtask.setTaskId(sd.getTaskId());
        subtask.setDuid(duid);
        subtask.setNeedTimes(Math.min(sd.getRemainSum(), sd.getSubtaskScriptSize()));
        subtask.setSuccessTimes(0);
        subtask.setFailTimes(0);
        subtask.setTaskStatus(SubTaskStatus.CREATE.getValue());
        subtask.setOrderNum(sd.getDistributeCount()+1);
        subtask.setFailReason(StringUtils.EMPTY);
        subtask.setNeedCan(0);
        subtask.setNeedAuxiliary(0);
        subtask.setRetryOriginId(0L);
        subtask.setCreateTime(new Date());
        if(StringUtils.isNotEmpty(sd.getScriptIds())) {
            //分配脚本 修改sd
            distributeScript(sd, subtask);
        }
        subtask.setMonkeyExeNumber(sd.getMonkeyExeNumber());
        subtask.setPackages(sd.getPackages());
        return subtask;
    }

    private void distributeScript(SubtaskDistribute sd, Subtask subtask){
        List<String> taskScriptList = this.getScriptIdListByParse(sd.getScriptIds());
        List<String> subtaskScriptList = new ArrayList<>();
        int remainNum = sd.getRemainSum();
        int subtaskLen = getSubtaskLen();
        int index = sd.getLastSubtaskEndScriptIndex();
        for(int i = 0; i<remainNum && i<subtaskLen; i++, index++){
            if(index > taskScriptList.size() - 1){
                index = 0;
            }
            String scpt = taskScriptList.get(index);
            subtaskScriptList.add(scpt);

            //剩余要分配数量
            sd.setRemainSum(sd.getRemainSum()-1);
            //已分配脚本数量
            sd.setExecSum(sd.getExecSum() +1);
        }
        //最后subtask脚本的在整个任务脚本中的序号
        sd.setLastSubtaskEndScriptIndex(index);
        //子任务数
        sd.setSubtaskCount(sd.getSubtaskCount()+1);
        subtask.setScriptIds(buildString(subtaskScriptList));//计算
    }

    private int getSubtaskLen(){
        return SUBTASK_LEN;
    }

    private boolean isScriptNeedCanBySubtask(Subtask subtask, List<String> canIds){
        if(CollectionUtils.isNotEmpty(canIds)){
            List<String> scripts = Arrays.asList(subtask.getScriptIds().split(","));
            for(String sid:canIds){
                if(scripts.contains(sid)){
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isScriptNeedAuxBySubtask(Subtask subtask, List<String> auxIds){
        if(CollectionUtils.isNotEmpty(auxIds)){
            List<String> scripts = Arrays.asList(subtask.getScriptIds().split(","));
            for(String auxid:auxIds){
                if(scripts.contains(auxid)){
                    return true;
                }
            }
        }
        return false;
    }

    private boolean isScriptNeedAllBySubtask(Subtask subtask, List<String> canIds,List<String> auxIds){
        boolean needCan = isScriptNeedCanBySubtask(subtask, canIds);
        boolean needAux = isScriptNeedAuxBySubtask(subtask, auxIds);
        return needCan && needAux;
    }

    private void build(RetryToDispatchGroup retryGroup, long taskId){
        List<Subtask> subtaskList = repository.getSubtaskListNeedSupportAndRetryByTaskId(taskId, true, true);
        retryGroup.setNeedAllList(subtaskList);
        List<Subtask> subtaskList2 = repository.getSubtaskListNeedSupportAndRetryByTaskId(taskId, true, false);
        retryGroup.setNeedCanList(subtaskList2);
        List<Subtask> subtaskList3 = repository.getSubtaskListNeedSupportAndRetryByTaskId(taskId, false, true);
        retryGroup.setNeedAuxiliaryList(subtaskList3);
        List<Subtask> subtaskList4 = repository.getSubtaskListNeedSupportAndRetryByTaskId(taskId, false, false);
        retryGroup.setNoNeedList(subtaskList4);
    }

    private void build(WaitToDispatchGroup waitGroup, long taskId){
        List<Subtask> subtaskList = repository.getSubtaskListNeedSupportAndWaitSendByTaskId(taskId, true, true);
        waitGroup.setNeedAllList(subtaskList);
        List<Subtask> subtaskList2 = repository.getSubtaskListNeedSupportAndWaitSendByTaskId(taskId, true, false);
        waitGroup.setNeedCanList(subtaskList2);
        List<Subtask> subtaskList3 = repository.getSubtaskListNeedSupportAndWaitSendByTaskId(taskId, false, true);
        waitGroup.setNeedAuxiliaryList(subtaskList3);
        List<Subtask> subtaskList4 = repository.getSubtaskListNeedSupportAndWaitSendByTaskId(taskId, false, false);
        waitGroup.setNoNeedList(subtaskList4);
    }

    /**
     * 硬件优先，再时间优先，获取需要分发的已分配子任务
     * @param retryGroup 重试
     * @param waitGroup  等待
     * @param taskDevice taskDevice
     * @param sd 分配记录
     * @return  Subtask
     */
    private Subtask getDisptchSubtaskByEquipPrior
            (RetryToDispatchGroup retryGroup, WaitToDispatchGroup waitGroup, TaskDevice taskDevice, SubtaskDistribute sd){
        Subtask subtask;
        //有硬件条件
        if(isTaskSupportCanOrAuxiliary(sd)){
            //can和辅助都支持
            if(isDeviceSupportCanAndAuxiliary(taskDevice)){
                //重试的，时间优先
                if(CollectionUtils.isNotEmpty(retryGroup.getNeedAllList())){
                    subtask = retryGroup.getNeedAllList().get(0);
                    return subtask;
                }else if(CollectionUtils.isNotEmpty(waitGroup.getNeedAllList())) {
                    subtask = waitGroup.getNeedAllList().get(0);
                    return subtask;
                }
            }
            if(isDeviceSupportCan(taskDevice)){
                //支持can
                if(CollectionUtils.isNotEmpty(retryGroup.getNeedCanList())){
                    subtask = retryGroup.getNeedCanList().get(0);
                    return subtask;
                }else if(CollectionUtils.isNotEmpty(waitGroup.getNeedCanList())) {
                    subtask = waitGroup.getNeedCanList().get(0);
                    return subtask;
                }
            }
            if(isDeviceSupportCanAndAuxiliary(taskDevice)){
                //支持辅助设备
                if(CollectionUtils.isNotEmpty(retryGroup.getNeedAuxiliaryList())){
                    subtask = retryGroup.getNeedAuxiliaryList().get(0);
                    return subtask;
                }else if(CollectionUtils.isNotEmpty(waitGroup.getNeedAuxiliaryList())) {
                    subtask = waitGroup.getNeedAuxiliaryList().get(0);
                    return subtask;
                }
            }
        }
        if(CollectionUtils.isNotEmpty(retryGroup.getNoNeedList())){
            subtask = retryGroup.getNoNeedList().get(0);
            return subtask;
        }else if(CollectionUtils.isNotEmpty(waitGroup.getNoNeedList())) {
            subtask = waitGroup.getNoNeedList().get(0);
            return subtask;
        }
        return null;
    }


    //设备优先，获取需分发的subtask，先从重试集合里面拿，在从待分发集合里拿
    //时间优先，从重试无设备里面拿，从创建待分发(无设备支持)里面拿
    //创建待分发，如果支持，那么发送


    private boolean isDeviceSupportCanAndAuxiliary(TaskDevice taskDevice){
        return taskDevice.getSupportCan().intValue() > 0
                && taskDevice.getSupportAuxiliary().intValue() > 0;
    }

    private boolean isDeviceSupportCan(TaskDevice taskDevice){
        return taskDevice.getSupportCan().intValue() > 0;
    }

    private boolean isDeviceSupportAuxiliary(TaskDevice taskDevice){
        return taskDevice.getSupportAuxiliary().intValue() > 0;
    }

    private boolean isTaskSupportCanOrAuxiliary(SubtaskDistribute sd){
        List<TaskDevice> tdList = repository.getTaskDeviceListById(sd.getTaskId().intValue());
        if(CollectionUtils.isEmpty(tdList)){
            return false;
        }
        if(sd.getDeviceSupportAuxiliary() > 0) {
            for (TaskDevice td : tdList) {
                if(td.getSupportAuxiliary()>0){
                    return true;
                }
            }
            //没有支持辅助设备的设备
            return false;
        }
        if(sd.getDeviceSupportCan() > 0) {
            for (TaskDevice td : tdList) {
                if(td.getSupportCan()>0){
                    return true;
                }
            }
            //没有支持can的设备
            return false;
        }
        return false;
    }



    public void handleTaskCreate(ITaskEvent event){
        if(!event.getDataType().equals(TaskDTO.class)){
            log.error("event datatype not match");
            return;
        }
        TaskDTO task = JSONObject.parseObject(event.getData(), TaskDTO.class);
        SubtaskDistribute subtaskDistribute = new SubtaskDistribute();
        buildSubtaskDistribute(subtaskDistribute, task);
        repository.createSubtaskDistribute(subtaskDistribute);
    }

    public void buildSubtaskDistribute(SubtaskDistribute subtaskDistribute, TaskDTO task){
        List<TaskDevice> taskDeviceList = repository.getTaskDeviceListById(task.getId());
        List<String> canScriptList = new ArrayList<>();
        List<String> auxiliaryScriptList = new ArrayList<>();
        if(StringUtils.isNotEmpty(task.getScriptIds())) {
            List<Integer> scriptIdList = parseScriptIdList(task.getScriptIds());
            List<ScriptInfo2> scriptList = repository.getScriptInfoListByIdList(scriptIdList);

            subtaskDistribute.setScriptIds(task.getScriptIds());
            subtaskDistribute.setScriptSize(scriptIdList.size());

            for(ScriptInfo2 script : scriptList){
                if(script.getSupportCan() > 0){
                    canScriptList.add(String.valueOf(script.getId()));
                }
                if(script.getSupportAuxiliary()>0){
                    auxiliaryScriptList.add(String.valueOf(script.getId()));
                }
            }
            subtaskDistribute.setNeedExecSum(task.getExeNumber()*scriptIdList.size());
        }else {
            subtaskDistribute.setNeedExecSum(task.getExeNumber());
        }
        subtaskDistribute.setTaskId(Long.valueOf(task.getId()));
        subtaskDistribute.setPackages(task.getPackages());
        subtaskDistribute.setMonkeyExeNumber(task.getMonkeyExeNumber());
        subtaskDistribute.setCanScriptIds(buildString(canScriptList));
        subtaskDistribute.setAuxiliaryScriptIds(buildString(auxiliaryScriptList));
        subtaskDistribute.setLastSubtaskEndScriptIndex(0);
        subtaskDistribute.setExecSum(0);
        subtaskDistribute.setRemainSum(subtaskDistribute.getNeedExecSum());
        subtaskDistribute.setSubtaskScriptSize(Math.min(subtaskDistribute.getNeedExecSum(), SUBTASK_LEN));
        subtaskDistribute.setDistributeCount(0);
        subtaskDistribute.setLastSubtaskId(0L);
        subtaskDistribute.setRetrySubtaskIds(StringUtils.EMPTY);
        subtaskDistribute.setLastRetrySubtask(0L);
        subtaskDistribute.setNeedCan(canScriptList.isEmpty()?0:1);
        subtaskDistribute.setNeedAuxiliary(auxiliaryScriptList.isEmpty()?0:1);
        for(TaskDevice taskDevice: taskDeviceList) {
            if(taskDevice.getSupportAuxiliary()>0) {
                subtaskDistribute.setDeviceSupportAuxiliary(SUPPORT_AUXILIARY_VALUE);
            }
            if(taskDevice.getSupportCan()>0){
                subtaskDistribute.setDeviceSupportCan(SUPPORT_CAN_VALUE);
            }
        }
        subtaskDistribute.setCreateTime(new Date());
    }

    private List<Integer> parseScriptIdList(String ids){
        List<Integer> scriptIdList = new ArrayList<>();
        if(StringUtils.isEmpty(ids)){
            return scriptIdList;
        }
        if(!ids.contains(",")){
            scriptIdList.add(Integer.valueOf(ids));
            return scriptIdList;
        }
        String[] idStrs = ids.split(",");
        for(String str:idStrs){
            if(StringUtils.isNotEmpty(str)){
                scriptIdList.add(Integer.valueOf(str));
            }
        }
        return scriptIdList;
    }

    private List<String> getScriptIdListByParse(String ids){
        List<String> scriptIdList = new ArrayList<>();
        if(StringUtils.isEmpty(ids)){
            return scriptIdList;
        }
        if(!ids.contains(",")){
            scriptIdList.add(ids);
            return scriptIdList;
        }
        String[] idStrs = ids.split(",");
        for(String str:idStrs){
            if(StringUtils.isNotEmpty(str)){
                scriptIdList.add(str);
            }
        }
        return scriptIdList;
    }

    private String buildString(List<String> list, String regx){
        if(CollectionUtils.isEmpty(list)){
            return StringUtils.EMPTY;
        }
        StringBuilder stringBuilder = new StringBuilder();
        for(Object obj : list){
            stringBuilder.append(obj).append(regx);
        }
        stringBuilder.deleteCharAt(stringBuilder.length()-1);
        return stringBuilder.toString();
    }

    private String buildString(List<String> list){
        return buildString(list, SEPARATOR);
    }

    /**
     * 同一时间多线程之间互斥即可
     * @param taskId 任务Id
     * @return 加锁成功与否
     */
    private boolean tryLock(String taskId) {
        if(StringUtils.isEmpty(taskId)){
            return false;
        }
        String key = JOB_SUBTASK_DISTRIBUTE_INSTANCE + ":" + taskId;
        try {
            boolean rslt = stringRedisTemplate.opsForValue().setIfAbsent(key, taskId, REDIS_KEY_DUID_EXPIRE_SECOND, TimeUnit.SECONDS);
            return rslt;
        }catch (Exception e){
            log.error("",e);
        }
        return false;
    }

    /**
     * 解锁
     * @param taskId 任务Id
     *
     */
    private void unLock(String taskId) {
        if(StringUtils.isEmpty(taskId)){
            return ;
        }
        stringRedisTemplate.delete(JOB_SUBTASK_DISTRIBUTE_INSTANCE + ":" + taskId);
    }

    @Override
    public String getBussinessType() {
        return DistributeManager.class.getSimpleName();
    }

}
